package com.hxzy.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hxzy.shop.cachedao.AuthCacheService;
import com.hxzy.shop.common.dto.auth.AuthMapStructConvert;
import com.hxzy.shop.common.dto.auth.req.*;
import com.hxzy.shop.common.dto.auth.resp.AccountResp;
import com.hxzy.shop.common.dto.auth.resp.RoleAuthorityTreeResp;
import com.hxzy.shop.common.dto.auth.resp.RoleListResp;
import com.hxzy.shop.constant.AuthConstant;
import com.hxzy.shop.constant.RedisConstant;
import com.hxzy.shop.dto.auth.resp.LoadUserResp;
import com.hxzy.shop.dto.auth.resp.ModuleCopyResp;
import com.hxzy.shop.dto.auth.resp.ModuleResp;
import com.hxzy.shop.entity.AdminModule;
import com.hxzy.shop.entity.AdminRole;
import com.hxzy.shop.entity.AdminRoleInnerModule;
import com.hxzy.shop.entity.Merchant;
import com.hxzy.shop.mapper.*;
import com.hxzy.shop.service.AuthService;
import com.hxzy.shop.utils.WebUtil;
import com.hxzy.shop.vo.ApiException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 功能描述 认证授权服务
 *
 * @author tonneyyy
 */
@Service
public class AuthServiceImpl implements AuthService {

    @Resource
    private HttpServletRequest request;

    @Resource
    private AccountMapper accountMapper;

    @Resource
    private StoreMapper storeMapper;

    @Resource
    private StoreAccountMapper storeAccountMapper;

    @Resource
    private BackAccountMapper backAccountMapper;

    @Resource
    private MerchantMapper merchantMapper;

    /**
     * 总部模块表 （商户版本 1：标准版，2：专业版 3：高级版 4：旗舰版）
     */
    @Resource
    private ModuleMapper moduleMapper;

    /**
     * 后台账户拥有的菜单
     */
    @Resource
    private AdminMenuMapper adminMenuMapper;

    /**
     * adminRole角色
     */
    @Resource
    private AdminRoleMapper adminRoleMapper;

    /**
     * admin_role_inner_module 角色与模块关联表
     */
    @Resource
    private AdminRoleInnerModuleMapper adminRoleInnerModuleMapper;

    /**
     * 角色账户关联表
     */
    @Resource
    private AdminAccountInnerRoleMapper adminAccountInnerRoleMapper;

    @Resource
    private AuthCacheService authCacheService;

    /**
     * 获取用户信息(包含菜单权限)
     * @param accountId
     * @return
     */
    @Override
    public LoadUserResp loadUser(Long accountId) {
        // 得到商家ID
        Long merchantId = Long.parseLong(WebUtil.getRequest().getHeader(AuthConstant.MERCHANT_ID));
        Merchant merchant = merchantMapper.selectById(merchantId);
        //根据账户ID查询用户信息和拥有的角色菜单权限
        LoadUserResp resp = this.accountMapper.findAccountAndRoleByAccountId(accountId);
        if (ObjectUtil.isEmpty(resp)) {
            throw new ApiException(500, "账号不存在");
        }

        //得到用户角色id
        String roleId = resp.getRoleId();

        //根据角色ID和商户购买的版本，查询菜单（商户版本 1：标准版，2：专业版 3：高级版 4：旗舰版）
        //List<AdminModule> moduleList=this.moduleMapper.findModuleByRoleId(roleId,merchant.getTypenoInt());

        //根据角色来查询拥有的模块
        List<AdminModule> moduleList = adminMenuMapper.getByAdminModuleList(roleId);
        if (!CollUtil.isEmpty(moduleList)) {
           //构建前端拥有的菜单模型
            List<ModuleResp> moduleRespList = new ArrayList<>();

            //除主除以外进行分组
            Map<Long, List<AdminModule>> groupMap = moduleList.stream().filter(f -> f.getPid() != 0).collect(Collectors.groupingBy(AdminModule::getPid));

            //循环遍历二级目录，把它放到一级目录中去
            groupMap.forEach((k,v)-> {
                ModuleResp moduleResp = new ModuleResp();
                //从父模块中查询子模块,得到父模块,相当于某个一id=k 并且 pid=0的值
                AdminModule module = moduleList.stream().filter(f -> f.getId().equals(k)).findFirst().orElseThrow(() -> new ApiException(500, "不可能为空"));
                moduleResp.setModuleId(module.getId());
                moduleResp.setPid(module.getPid());
                moduleResp.setIcon(module.getIcon());
                moduleResp.setName(module.getName());
                moduleResp.setSort(module.getSort());
                moduleResp.setUrl(module.getUrl());
                moduleResp.setShowUrl(module.getShowUrl());
                moduleResp.setActiveMenu(module.getActiveMenu());
                moduleResp.setApiUrl(module.getApiUrl());

                //设定子模块
                List<ModuleResp> childModule = v.stream().map(m -> {
                    ModuleResp moduleSon = new ModuleResp();
                    moduleSon.setPid(m.getPid());
                    moduleSon.setUrl(m.getUrl());

                    moduleSon.setIcon(m.getIcon());
                    moduleSon.setName(m.getName());
                    moduleSon.setSort(m.getSort());
                    moduleSon.setApiUrl(m.getApiUrl());
                    moduleSon.setShowUrl(m.getShowUrl());
                    moduleSon.setModuleId(m.getId());
                    moduleSon.setActiveMenu(m.getActiveMenu());
                    return moduleSon;
                }).sorted(Comparator.comparing(ModuleResp::getSort)).collect(Collectors.toList());

                moduleResp.setModules(childModule);

                //添加到集合中去
                moduleRespList.add(moduleResp);
            });

            //最后再排一次序
            List<ModuleResp> list = moduleRespList.stream().sorted(Comparator.comparing(ModuleResp::getSort)).collect(Collectors.toList());
            resp.setModules(list);
        }

        return resp;
    }


    /************************* admin-role ---------------------------*/

    /**
     * admin_role分页查询
     * @param req
     * @return
     */
    @Override
    public PageInfo<RoleListResp> roleList(RoleListReq req) {
        return PageHelper.startPage(req.getPageNum(),req.getPageSize()).doSelectPageInfo(()->{
            adminRoleMapper.roleList(req);
        });
    }

    /**
     * 根据admin_role表中主键查询
     * @param roleId
     * @return
     */
    @Override
    public AdminRole roleDetail(Long roleId) {
        return adminRoleMapper.selectById(roleId);
    }

    @Override
    public int editRole(EditRoleReq req) {
        AdminRole db = this.adminRoleMapper.selectById(req.getRoleId());
        if (ObjectUtil.isEmpty(db)) {
            throw new ApiException(500, "角色不存在");
        }

        db.setRoleName(req.getRoleName());
        db.setRoleDescription(req.getRoleDescription());
        db.setState(req.getState());
        db.setUpdateTime(new Date());
        return this.adminRoleMapper.updateById(db);
    }

    @Override
    public int addRole(AddRoleReq req) {
       AdminRole role= AuthMapStructConvert.INSTANCE.toEntity(req);
       role.setRoot(false);
       role.setCreateTime(new Date());
        return this.adminRoleMapper.insert(role);
    }

    /**
     * 更改角色状态
     * @param req
     * @return
     */
    @Override
    public int changeRoleState(ChangeRoleStateReq req) {
        AdminRole db = this.adminRoleMapper.selectById(req.getRoleId());
        if(Objects.isNull(db)){
            throw new ApiException(500, "角色不存在");
        }

        if(db.getRoot()){
            throw new ApiException(500, "初始化角色状态不能修改");
        }

        db.setState(!db.getState());
        db.setUpdateTime(new Date());

        return this.adminRoleMapper.updateById(db);
    }

    /**
     * 角色权限树
     * @param roleId
     * @return
     */
    @Override
    public List<RoleAuthorityTreeResp> roleAuthorityTree(Long roleId) {
        Long merchantId = Long.parseLong(WebUtil.getRequest().getHeader(AuthConstant.MERCHANT_ID));
        Merchant merchant = merchantMapper.selectById(merchantId);

        //得到商家的菜单模块（根据商户ID查询）
        List<ModuleCopyResp> allModule = adminMenuMapper.getByAdminMenuList();
       //得到商户的角色ID分配的module  总部角色模块关联表（admin_module和admin_role_inner_module）
        List<Long> moduleIds = this.adminRoleInnerModuleMapper.findModuleIdByRoleId(roleId);

        List<RoleAuthorityTreeResp> list = new ArrayList<>();

        //除以pid=0以外的汇总  Map<Pid,List>
        Map<Long, List<ModuleCopyResp>> groupMap;

        //如果之前角色分配权限的
        if (!CollUtil.isEmpty(moduleIds)) {
            groupMap = allModule
                    .stream()
                    .peek(p -> {
                        if (moduleIds.contains(p.getModuleId())) {
                            p.setMark(Boolean.TRUE);
                        } else {
                            p.setMark(Boolean.FALSE);
                        }
                    })
                    .filter(f -> f.getPid() != 0)
                    .collect(Collectors.groupingBy(ModuleCopyResp::getPid));
        } else {
            groupMap = allModule
                    .stream()
                    .peek(p -> p.setMark(Boolean.FALSE))
                    .filter(f -> f.getPid() != 0)
                    .collect(Collectors.groupingBy(ModuleCopyResp::getPid));
        }

        //二级节点进行排序 sort
        groupMap.forEach((k, v) -> {
            List<RoleAuthorityTreeResp> sonList = v.stream()
                    .map(m -> {
                        RoleAuthorityTreeResp sonResp = new RoleAuthorityTreeResp();
                        sonResp.setModuleId(m.getModuleId());
                        sonResp.setName(m.getName());
                        sonResp.setMark(m.getMark());
                        sonResp.setSort(m.getSort());
                        sonResp.setActiveMenu(m.getActiveMenu());
                        sonResp.setShowUrl(m.getShowUrl());
                        return sonResp;
                    }).sorted(Comparator.comparing(RoleAuthorityTreeResp::getSort)).collect(Collectors.toList());

            //查询父节点
            ModuleCopyResp moduleResp = allModule.stream().filter(f -> f.getModuleId().equals(k)).findFirst().orElseThrow(() -> new ApiException(500, "不可能为空"));
            //构造一级节点
            RoleAuthorityTreeResp resp = new RoleAuthorityTreeResp();
            resp.setModuleId(moduleResp.getModuleId());
            resp.setName(moduleResp.getName());
            resp.setSort(moduleResp.getSort());
            resp.setActiveMenu(moduleResp.getActiveMenu());
            resp.setShowUrl(moduleResp.getShowUrl());
            //设定子节点
            resp.setSonModule(sonList);
            //如果所有的子节点都选中，父节点才被设定为选中
            resp.setMark(sonList.stream().allMatch(RoleAuthorityTreeResp::getMark));
            list.add(resp);

        });

        //排序所有的节点
        List<RoleAuthorityTreeResp> collect = list.stream().sorted(Comparator.comparing(RoleAuthorityTreeResp::getSort)).collect(Collectors.toList());

        return collect;
    }

    /**
     * 修改角色权限
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int changeRoleAuthority(ChangeRoleAuthorityReq req) {
        AdminRole db = this.adminRoleMapper.selectById(req.getRoleId());
        if (ObjectUtil.isEmpty(db)) {
            throw new ApiException(500, "角色不存在");
        }
        if (db.getRoot()) {
            throw new ApiException(500, "不能修改初始化角色的权限树");
        }

        //先删除原先拥有的权限
        QueryWrapper<AdminRoleInnerModule> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("role_id",req.getRoleId());
        this.adminRoleInnerModuleMapper.delete(queryWrapper);

        //再循环插入新的权限
        req.getModuleIds().forEach(c->{
            AdminRoleInnerModule roleInnerModule = new AdminRoleInnerModule();
            roleInnerModule.setRoleId(req.getRoleId());
            roleInnerModule.setModuleId(c);
            adminRoleInnerModuleMapper.insert(roleInnerModule);
        });


        this.emptyToken(req.getRoleId());

        return 1;
    }

    @Override
    public void emptyToken(Long roleId) {
        List<AccountResp> accountList = adminAccountInnerRoleMapper.findAccountByRoleId(roleId);
        if (!CollUtil.isEmpty(accountList)) {
            CompletableFuture.runAsync(() ->
                    accountList.forEach(c -> {
                        String key = RedisConstant.AUTHORIZATION + AuthConstant.ADMIN_CLIENT_ID + ":" + c.getAccount() + c.getMerchantId();
                        authCacheService.emptyToken(key);
                    }));
        }
    }


}
